program main
    implicit none
	open(form="formatted", unit=11, file="lesson1.txt")
	call version77
	call version90
	call part2
end program

subroutine version77
	real y(10)
	real x(10)
	common /mycom/ x
    integer i
	parameter(pi = 3.14159)

	do i = 1, 10
	   x(i) = i / 10.0
	   y(i) = sin(x(i) * pi)
	enddo	
	write(11, *), "Version 77"
	write(11, *), (y(i), i = 1, 10)
end 

module precision
	implicit none
	integer, parameter:: adequate = selected_real_kind (6,35)
	integer, parameter:: precise = selected_real_kind (14,99)
	real(adequate), parameter:: pi = 3.14159_adequate
end module precision

module mystuff
	use precision
	implicit none
	real(adequate) x(10)
	interface
	   function version3(x) result(y)
	      use precision
	      real(adequate), intent(in):: x(:)
		  real(adequate) y(size(x))
	   end function version3

	   subroutine version7(x)
		  use precision
		  real(adequate), intent(in):: x(:)
	   end subroutine version7
	end interface
end module mystuff

subroutine version90
	use mystuff
	implicit none
    integer i

	do i = 1, 10
	   x(i) = i / 10.0
	enddo
	call version0
	call version1
	call version2
	write(11, *), "Version 3"
	write(11, *), version3(x)
	call version4 (x, 10)
	call version5 (x, 10)
	call version6 (x(1), 10)
	call version7 (x)
end

subroutine version0
	use mystuff
	implicit none
	real(adequate) y(10)

	y = sin(x * pi)
	write(11, *), "Version 0"
	write(11, *), y
end subroutine version0

subroutine version1
! first improvement: no need to hard-wire sizes
	use mystuff
	implicit none
	real(adequate) y(size(x))

	y = sin(x * pi)
	write(11, *), "Version 1"
	write(11, *), y
end subroutine version1

subroutine version2
! if you don't know the right size on entry, use allocatable arrays
	use mystuff
	implicit none
	real(adequate), allocatable:: y(:)
	integer ierr 

	do
	   allocate(y(size(x)), stat = ierr)
	   if(ierr > 0) exit !! leave the do block
	   y = sin(x * pi)
	   write(11, *), "Version 2"
	   write(11, *), y
	   return
	enddo
	write(11, *) "Version 2 failed allocating memory."
end subroutine version2

function version3 (x) result(y)
! same ideas work for arguments and function results
	use precision
	implicit none
	real(adequate), intent(in):: x(:)
	real(adequate) y(size(x))

	y = sin(x * pi)
end function version3

subroutine version4 (x, n) 
! Sizes can also be picked up from other variables
	use precision
	implicit none
	integer, intent(in):: n
	real(adequate), intent(in):: x(n)
	real(adequate) y(n)

	y = sin(x * pi)
	write(11, *), "Version 4"
	write(11, *), y
end subroutine version4

subroutine version5 (x, n) 
! F77's assumed-size array supported for compatibility, legacy code
	use precision
	implicit none
	integer, intent(in):: n
	real(adequate), intent(in):: x(*) ! assumed-size array
	real(adequate) y(n)

!	y = sin(x * pi) compiler error, doesn't know the size of x
	y = sin(x(1:n) * pi)	! o.k.
    write(11, *), "Version 5"
	write(11, *), y
end subroutine version5

subroutine version6 (x, n) 
! Same as version 5, only called with x(1)
	use precision
	implicit none
	integer, intent(in):: n
	real(adequate), intent(in):: x(*) ! assumed-size array
	real(adequate) y(n)

	y = sin(x(1:n) * pi)
    write(11, *), "Version 6"
	write(11, *), y
end subroutine version6

subroutine version7 (x)
	use precision
	implicit none
	real(adequate), intent(in), target:: x(:)
	real(adequate), pointer:: y(:), z(:)
	integer n, m

	n = lbound(x, 1)
	m = ubound(x, 1)
	y => x(n+1: m)
	z => x(n: m - 1)
	write(11, *), "Version 7"
	write(11, *), z - y
end subroutine version7

